import React, { useState, useContext, useEffect } from "react";

var setState = (newState) => {
  store.state = newState;
  store.listeners.map((fn) => fn(store.state));
};

const store = {
  state: undefined,
  reducer: undefined,
  dispatch: (action) => {
    setState(store.reducer(store.state, action));
  },
  listeners: [],
  subscribe(fn) {
    store.listeners.push(fn);
    return () => {
      const index = store.listeners.indexOf(fn);
      store.listeners.splice(index, 1);
    };
  },
};

// 支持异步action
// 拦截dispatch
var dispatch = store.dispatch;
const prevDispatch = dispatch;

// 调用逻辑
// dispatch({type: xxx ,payload})
// dispatch(() => {})
dispatch = (action) => {
  if (action instanceof Function) {
    // 如果是函数 dispatch递归
    // 函数执行完以后 也有可能继续函数请求 也有可能直接调用dispatch修改数据
    action(dispatch);
  } else {
    // 如果是对象 直接调用原来的dispatch
    prevDispatch(action);
  }
};

// 支持调用 action.payload 异步
var dispatch = store.dispatch;
const payloadDispatch = dispatch;

// 调用逻辑
// dispatch({type: xxx， payload: require({url: 'xxx'}).then(res => {})})
dispatch = (action) => {
  if (action.payload instanceof Promise) {
    action.payload.then((data) => {
      console.log("data ====> ", data);
      dispatch({ ...action, payload: data });
    });
  } else {
    console.log("action 对象走这里 ===>   ", action);
    console.log("payloadDispatch ===> ", payloadDispatch);
    payloadDispatch(action);
  }
};

// 一般情况下 reducer 和 state 的默认值 是我们外部传入的 而不是内部定义的
export const createStore = (initState, reducer) => {
  store.state = initState;
  store.reducer = reducer;

  return store;
};

export const appContext = React.createContext(null);

const changeData = (oldData, newData) => {
  let check = false;
  for (const key in newData) {
    if (newData[key] !== oldData[key]) {
      check = true;
    }
  }
  return check;
};

export const Connect = (selector, dispatchSelector) => (Component) => {
  const Wrapper = (props) => {
    const { state, setState } = useContext(appContext);
    const [, update] = useState({});

    //  mapStateToProps
    const data = selector ? selector(state) : { state };
    //  mapDispatchToProps
    // const dispatch = store.dispatch;
    const methdos = dispatchSelector
      ? dispatchSelector(dispatch)
      : { dispatch };

    useEffect(
      () =>
        store.subscribe(() => {
          const newData = selector
            ? selector(store.state)
            : { state: store.state };
          if (changeData(data, newData)) {
            update({});
          }
        }),
      [selector]
    );

    return <Component {...props} {...methdos} {...data} />;
  };

  return Wrapper;
};

// main
export const Provider = ({ store, children }) => {
  return <appContext.Provider value={store}>{children}</appContext.Provider>;
};
